<html>
<head>
<!--
  Copyright 2009 Google Inc.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
-->
  <title>GEarthExtensions Test Runner</title>
  <script src="http://www.google.com/jsapi?key=ABQIAAAAsc0UQXoo2BnAJLhtpWCJFBTgHOxFyKCf35LCvsI_n4URElrkIhS9MkSlm_0NZWgrKFkOsnd5rEK0Lg" type="text/javascript"></script>
  <script src="jsUnitCore.js" type="text/javascript"></script>
  <script src="geoTestCore.js" type="text/javascript"></script>
  <script src="geo.js" type="text/javascript"></script>
  <script src="extensions.js" type="text/javascript"></script>
  <script src="extensions.tests.js" type="text/javascript"></script>
<script type="text/javascript">
/* <![CDATA[ */

var testplugin_ = null;
var testext_ = null;

google.load('earth', '1');
google.setOnLoadCallback(function() {
  enableUI(false);
  google.earth.createInstance('map3d', function(pluginInstance) {
    enableUI(true);
    testplugin_ = pluginInstance;
    testplugin_.getWindow().setVisibility(true);
    testext_ = new GEarthExtensions(testplugin_);
  }, function() {});
});


function exposeTestFunctionNames() {
  var tests = {};
  
  if (navigator.userAgent.toLowerCase().indexOf('msie') >= 0) {
    // IE doesn't support enumerating custom members of window
    for (var i = 0; i < document.scripts.length; i++) {
      var scriptNode = document.scripts[i];
      var scriptBody = '';
      if (scriptNode.innerHTML) {
        scriptBody += scriptNode.innerHTML;
      }
      
      if (scriptNode.src) {
    		var xhr = new ActiveXObject('Msxml2.XMLHTTP');
    		xhr.open('get', scriptNode.src, false); // false -- not async
    		xhr.send();
    		scriptBody += xhr.responseText;
      }
      
      // parse script body for test_xx functions
      var possibleTests = scriptBody.match(/test_\w+/g);
      if (possibleTests) {
        for (var j = 0; j < possibleTests.length; j++) {
          if (possibleTests[j] in window &&
              typeof window[possibleTests[j]] === 'function')
            tests[possibleTests[j]] = true;
        }
      }
    }    
  } else {
    for (var f in window) {
      if (f.substr(0, 5) == 'test_' &&
          typeof window[f] === 'function')
        tests[f] = true;
    }
  }

  // convert into an array
  var testsArr = [];
  for (var test in tests) {
    testsArr.push(test);
  }

  testsArr.sort();
  return testsArr;
}

function clearResults() {
  document.getElementById('test-results').innerHTML = '';
}

function logResult(testName, pass, message) {
  document.getElementById('test-results').innerHTML +=
      '<li class="' + (pass ? 'pass' : 'fail') + '"><span class="test-name">' +
      testName.replace(/^test_/, '').toString() + '</span> ' +
      (message ? message : (pass ? 'pass' : 'fail')) + '</li>';
}

var TESTS_INTERACTIVE = 0x01;
var TESTS_AUTOMATED = 0x02;
var TESTS_ALL = TESTS_INTERACTIVE | TESTS_AUTOMATED;

function enableUI(enable) {
  var c = document.getElementById('run-buttons').firstChild;
  while (c) {
    if ('disabled' in c)
      c.disabled = enable ? false : true;
    c = c.nextSibling;
  }
}

function runTests(type) {
  if (!type)
    type = TESTS_ALL;
  
  clearResults();
  
  var testFnNames = exposeTestFunctionNames();
  var i = -1;
  
  function runNextTest() {
    enableUI(false);
    
    i++;
    if (i >= testFnNames.length) {
      enableUI(true);
      return;
    }
    
    // run test
    var testName = testFnNames[i];
    var testFn = window[testName];
    
    if (testFn.interactive) {
      if (!(type & TESTS_INTERACTIVE)) {
        runNextTest();
        return;
      }
    } else {
      if (!(type & TESTS_AUTOMATED)) {
        runNextTest();
        return;
      }
    }
    
    function makeSuccessFn(testName, testFn) {
      return function() {
        // log result and run next test
        logResult(testName, true);
        runNextTest();
      };
    }
    
    function makeErrorFn(testName, testFn) {
      return function(e) {
        var messages = [];
      
        if (e.message) {
          messages.push(new String(e.message));
        } else if (e.comment) {
          messages.push(new String(e.comment));
        } else if (e.description) {
          messages.push(new String(e.description));
        }
      
        if (e.jsUnitMessage) {
          messages.push('JSUnit Error: ' + new String(e.jsUnitMessage));
        }
      
        if (e.sourceURL) {
          messages.push('See ' + new String(e.sourceURL) +
              ' (Line ' + new String(e.line) + ')');
        }
      
        // TODO: use e.stackTrace
        // log result and run next test
        for (var k in e) {
          messages.push(k + ' = ' + e[k].toString());
        }
        
        logResult(testName, false, messages.join('<br>'));
        runNextTest();
      };
    }

    var runFunc = function() {
      if (testFn.interactive || testFn.async) {
        testFn.call(null,
            makeSuccessFn(testName, testFn),
            makeErrorFn(testName, testFn));
      } else {
        testFn.call(null);
        makeSuccessFn(testName, testFn)();
      }
    };

    var passExceptions = document.getElementById('passexceptions').checked;

    if (passExceptions) {
      runFunc.call();
    } else {
      try {
        runFunc.call();
      } catch (e) {
        makeErrorFn(testName, testFn)(e);
      }
    }
  }
  
  runNextTest();
}

/* ]]> */
</script>
<style type="text/css">
/* <![CDATA[ */
#test-results {
  font-family: helvetica, arial, sans-serif;
  font-size: 10pt;
  padding: 0 0 0 2em;
  margin: 0;
}

#test-results li {
  list-style: decimal outside none;
  border-bottom: 1px solid #ccc;
  padding: 2px;
}

#test-results li.pass {
  background-color: #cfc;
}

#test-results li.fail {
  background-color: #fcc;
}

#test-results li .test-name {
  font-weight: bold;
  color: #888;
}

#test-results li.fail .test-name {
  font-weight: bold;
  color: #f00;
}

#test-results li .test-name:after {
  content: ': ';
}
/* ]]> */
</style>
</head>
<body style="margin-right: 520px;">
  <div id="map3d-container" style="width: 500px; height: 500px; position: absolute; right: 10px; top: 10px;">
    <div id="map3d" style="height: 100%"></div>
  </div>
  
  <h1><code>GEarthExtensions</code> Test Runner</h1>
  <div id="run-buttons">
    <input type="button" onclick="runTests(TESTS_AUTOMATED)" value="Run Automated Tests"/>
    <input type="button" onclick="runTests(TESTS_ALL)" value="Run All Tests"/>
    <input type="checkbox" id="passexceptions"/>
    <label for="passexceptions">Debugging: Pass exceptions to browser?</label>
  </div>
  <ol id="test-results"></ol>
</body>
</html>
